为什么需要注册中心
之前实现的一对一微服务通信(一个客户端连接一个服务实例)在业务规模增大后会遇到瓶颈:
- 服务器资源有限:单实例无法支撑高并发请求
- 高可用需求:单点故障会导致整个服务不可用
- 动态扩缩容:需要运行时动态添加或移除服务实例
注册中心(Service Registry)就是解决这些问题的核心基础设施。
注册中心的三种角色
| 角色 | 职责 |
|---|---|
| 服务提供者(Provider) | 启动时向注册中心注册自己的地址和端口,停止时注销 |
| 服务消费者(Consumer) | 从注册中心获取服务列表,选择一个实例发起调用 |
| 注册中心(Registry) | 存储所有服务的注册信息,节点变更时同步更新 |
工作流程
1. Provider 启动 → 向 Registry 注册(IP:Port, 服务名称, 版本等)
2. Consumer 启动 → 向 Registry 订阅所需服务
3. Registry 推送服务列表给 Consumer
4. Consumer 根据负载均衡策略选择一个 Provider 实例
5. Provider 宕机 → Registry 检测到心跳丢失 → 通知 Consumer 更新列表
6. 新 Provider 上线 → Registry 检测到新实例 → 推送更新给 Consumer
text
核心能力
服务注册
服务启动时,将自己的元数据(IP、端口、服务名称、版本、权重等)注册到注册中心。
服务发现
消费者不需要硬编码服务地址,而是从注册中心动态获取可用的服务实例列表。
健康检查
注册中心定期(通过心跳或主动探测)检查服务实例是否存活。不健康的实例会被自动剔除。
变更通知
当服务实例发生变更(上线、下线、故障)时,注册中心主动通知订阅了该服务的消费者更新本地缓存。
从硬编码到动态发现
硬编码方式(之前)
ClientsModule.register([
{
name: 'USER_SERVICE',
transport: Transport.GRPC,
options: {
url: 'localhost:5000' // 写死地址
}
}
])
typescript
问题:如果需要启动多个用户服务实例(5001、5002、5003),或者实例地址发生变化,必须修改代码重新部署。
注册中心方式(之后)
// 服务启动时自动注册
// 消费者从注册中心获取地址列表
// 无需硬编码任何服务地址
typescript
这为微服务的弹性伸缩和高可用部署奠定了基础。
↑